import { isAbsoluteURL } from "./utils";
import $config from "../config";
import { Response } from "../type";
import store from "./store";

const { appName, osName, deviceBrand, appVersionCode, appWgtVersion, appVersion, uniPlatform } = uni.getSystemInfoSync();

export function requestInvoke(
  args: UniApp.RequestOptions & UniApp.UploadFileOption,
  paramsKey: "data" | "formData"
): UniApp.RequestOptions | UniApp.UploadFileOption {
  isAbsoluteURL(args.url) || /^\/(cex|static)\//.test(args.url) ||
    (args.url = ($config.URL_REMOTE || "") + ($config.API_PREFIX || "") + args.url);
  args.header ?? (args.header = {});
  args[paramsKey] ?? (args[paramsKey] = {});
  paramsKey === "data" && (args.header["Content-type"] = "application/json");
  args.header["lang"] = uni.getLocale();
  args.header["version"] = appWgtVersion || appVersion;

  const token = uni.getStorageSync($config.STORAGE_KEY_USER_INFO)?.value?.[$config.FIELD_TOKEN];
  if (token) { args.header[$config.FIELD_TOKEN] = token; }

  for (let key in args[paramsKey]) {
    if ([null, undefined, NaN].includes(args[paramsKey][key])) delete args[paramsKey][key];
  }
  return args;
}

const pretreatment = {
  debounce: false,
  login: ({ msg: content, data }: Response): Promise<string> | void => {
    if (pretreatment.debounce) return Promise.reject(content);
    pretreatment.debounce = true;

    const { liveTask, getMarketTask } = store.state;
    liveTask && clearInterval(liveTask);
    getMarketTask && clearInterval(getMarketTask);

    uni.showModal({
      title: "温馨提示",
      content: "请先登录后再操作",
      confirmText: "去登录",
      showCancel: false,
      success({ confirm, cancel }) {
        uni.removeStorage({ key: $config.STORAGE_KEY_USER_INFO });
        cancel && +data?.forcedLogin && uni.navigateBack();
        confirm && uni.navigateTo({
          url: [
            // #ifdef MP
            $config.PAGE_LOGIN_APPLETS,
            // #endif
            // #ifndef MP
            $config.PAGE_LOGIN_ACCOUNT
            // #endif
          ][0]
        });
      },
      complete: () => {
        pretreatment.debounce = false;
      }
    });
    return Promise.reject(content);
  },
  fail(res: Response): Promise<Response> {
    uni.showToast({ title: res.msg, icon: "none" });
    return Promise.reject(res)
  },
  success: (res: Response): Promise<Response> => Promise.resolve(res),
}

export function requestSuccess({ data, statusCode }: UniApp.RequestSuccessCallbackResult) {
  try {
    const res = (typeof data === "string") ? JSON.parse(data) : data,
      { success, login, fail } = pretreatment;
    switch (res.code) {
      case 1001:
        return fail(res);
      case 1007:
        return login(res);
      case undefined:
        throw new Error(res);
      default:
        return success(res);
    };
  } catch (error) {
    // DEBUG MODE
    const content = (typeof data === "string") ? (data || "服务器无响应") : JSON.stringify(data, null, 2);
    uni.showModal({
      title: `StatusCode ${statusCode}`,
      content,
      confirmText: "Copy",
      cancelText: "Cancel",
      success: ({ confirm }) =>
        confirm && uni.setClipboardData({ data: content.replace(/\n|\r|\t/g, "") })
    });
    return Promise.reject(content);
  }
}

export const requestInterceptorOptions = (paramsKey: "data" | "formData"): UniApp.InterceptorOptions => ({
  invoke: (args: UniApp.RequestOptions & UniApp.UploadFileOption):
    UniApp.RequestOptions | UniApp.UploadFileOption => requestInvoke(args, paramsKey),
  success: (res: UniApp.RequestSuccessCallbackResult) => requestSuccess(res),
  fail({ errMsg }: UniApp.GeneralCallbackResult): void {
    if (errMsg.includes("abort")) return;
    uni.showToast({ title: String(errMsg), icon: "none" });
  },
  complete(res: UniApp.GeneralCallbackResult): void {
    console.log(`%c Response`, "color: #5b6cf2;", res);
  },
});

export function connectWebsocket() {
  if (!$config.URL_WEBSOCKET) return;
  let [socketOpen, socketMsgQueue]: [boolean, string[]] = [false, []];

  uni.connectSocket({ url: $config.URL_WEBSOCKET });
  uni.onSocketOpen((res) => {
    socketOpen = true;
    for (let i = 0; i < socketMsgQueue.length; i++) {
      socketOpen
        ? uni.sendSocketMessage({ data: socketMsgQueue[i] })
        : socketMsgQueue.push(socketMsgQueue[i]);
    }
    socketMsgQueue = [];
    // uni.closeSocket({});
  });
  uni.onSocketMessage((res) => {
    console.log("Received server content:" + res.data);
  });
  uni.onSocketClose((res) => {
    socketOpen = false;
    console.log("Websocket closed!");
  });
  uni.onSocketError((res) => {
    console.log("Websocket connection opening failed, please check!");
  });
}

export function checkVersion({ showToast } = { showToast: false }) {
  // #ifndef APP-PLUS
  console.log(
    `%c ${appName} %c Version ${appWgtVersion || appVersion} %c`,
    "background: #35495e; padding: 1px; border-radius: 3px 0 0 3px; color: #fff",
    "background: #007aff; padding: 1px; margin: 1px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;",
    "background: transparent"
  );
  // #endif

  // #ifdef MP
  const { onCheckForUpdate, onUpdateReady, onUpdateFailed, applyUpdate } = uni.getUpdateManager();

  onCheckForUpdate(({ hasUpdate }) => {
    showToast && uni.showToast({ title: hasUpdate ? "发现新版本，正在更新..." : "已是最新版本！", icon: "none" });

    hasUpdate && console.log("New version found !");
  });

  onUpdateReady((res) => {
    uni.showModal({
      title: "Update Tips",
      confirmText: "Restart",
      cancelText: "Cancel",
      content:
        "The new version is ready. Do you want to restart the application?",
      success: ({ confirm }) => {
        uni.clearStorage();
        confirm && applyUpdate();
      },
    });
  });

  onUpdateFailed((res) => {
    uni.showToast({
      title: "Failed to download the new version. Please try again later.",
      icon: "none",
    });
  });
  // #endif


  function getLatestVersion(versionCode = appVersionCode) {
    uni.request({
      url: $config.API_CHECK_VERSION,
      data: { osName, appVersionCode: versionCode, brand: deviceBrand, platform: uniPlatform },
      success: <any>(({ data, msg: title }: Response) => {
        if (!data?.upgradeURL) {
          showToast && uni.showToast({ title, icon: "none" });
          return;
        };

        // #ifdef APP-PLUS
        uni.setStorage({
          key: "upgradeInfo",
          data: { title, ...data },
          success() {
            uni.navigateTo({ url: $config.PAGE_UPGRADE });
          }
        });
        // #endif

        // #ifdef H5
        const a = document.createElement("a");
        a.href = data.upgradeURL;
        a.download = `${appName}_v${appVersion}.apk`;
        a.click();
        // #endif
      }),
      fail({ errMsg: title }) {
        uni.showToast({ title, icon: "error" });
      }
    });
  }

  // #ifdef APP-PLUS
  console.log(`${appName} Version${appWgtVersion}`);
  if (!$config.API_CHECK_VERSION) return;
  plus.runtime.getProperty(plus.runtime.appid!, ({ versionCode }) => getLatestVersion(versionCode));
  // #endif

  // #ifdef H5
  getLatestVersion();
  // #endif
}

export async function setConfig() {
  const value = {};
  if ($config.API_CONFIG_GET) {
    const { data } = await <unknown>uni.request({ url: $config.API_CONFIG_GET }) as Response;
    data && Object.assign(value, data);
  };
  // #ifdef H5
  const { data } = await <unknown>uni.request({ url: `${$config.URL_ASSETS}/static/config.json` }) as Response;
  data && Object.assign(value, data);
  // #endif

  Object.keys(value).length && uni.setStorage({
    key: "$config",
    data: { $type: "update", value }
  });
}

export const beforeRouterInvoke = (url: string) => {
  const routes = getCurrentPages(),
    { route } = routes[routes.length - 1] || { route: "" };

  if (`/${route}` === $config.PAGE_LOGIN_ACCOUNT && `/${route}` === url) {
    return false;
  }

  if (/pages\/admin\/.*$/.test(url) && !uni.getStorageSync($config.STORAGE_KEY_USER_INFO)) {
    uni.navigateTo({ url: $config.PAGE_LOGIN_ACCOUNT });
    return false;
  }
  return true;
}
